package vn.vfriends.id.bean;

import java.io.Serializable;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.enterprise.context.SessionScoped;
import javax.faces.application.FacesMessage;
import javax.faces.context.FacesContext;
import javax.inject.Inject;
import javax.inject.Named;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.commons.codec.digest.DigestUtils;
import org.openid4java.message.Message;
import org.openid4java.message.ParameterList;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import vn.vfriends.id.jpa.controller.RoleJpaController;
import vn.vfriends.id.jpa.controller.UserJpaController;
import vn.vfriends.id.jpa.entity.Group;
import vn.vfriends.id.jpa.entity.Role;
import vn.vfriends.id.jpa.entity.User;
import vn.vfriends.id.openid.OpenIdProvider;

/**
 *
 * @author tuan@vfriends.vn
 */
@Named
@SessionScoped
public class SecurityBean implements Serializable {

    private Logger logger = LoggerFactory.getLogger(SecurityBean.class);
    private String username;
    private String password;
    private User loggedUser;
    @Inject private UserJpaController userController;
    @Inject private RoleJpaController roleController;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public User getLoggedUser() {
        if(loggedUser == null) {
            FacesContext context = FacesContext.getCurrentInstance();
            HttpServletRequest request = (HttpServletRequest) context.getExternalContext().getRequest();
            HttpSession session = request.getSession();
            loggedUser = (User)session.getAttribute("LOGGED_USER");
        }
            
        return loggedUser;
    }
    
    public String loginAction() {
        FacesContext context = FacesContext.getCurrentInstance();
        String outcome = "";
        try {
            User user = this.userController.findByUsername(username);
            if(user == null || !user.getPassword().equals(DigestUtils.md5Hex(password))) {
                context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Login failed", ""));
            } if(!user.isIsActivated()) {
                context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "This user is not activated", ""));
            } else {
                loggedUser = user;
                HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getRequest();
                HttpSession session = request.getSession();
                session.setAttribute("LOGGED_USER", loggedUser);
                
                // Get roles of logged user
                List<Group> groupList = loggedUser.getGroups();
                Set<Role> roleSet = new HashSet<Role>();
                for(Group group : groupList) {
                    List<Role> roleList = group.getRoles();
                    for(Role role : roleList) {
                        roleSet.add(role);
                    }
                }
                session.setAttribute("LOGGED_USER_ROLES", roleSet);
                
                if(session.getAttribute("OPENID_PARAMS") != null) {
                    ParameterList requestParameters = (ParameterList)session.getAttribute("OPENID_PARAMS");
                    String userSelectedId = OpenIdProvider.getOpEndpointUrl();
                    String userSelectedClaimedId = OpenIdProvider.getOpEndpointUrl();
                    // Create the AuthResponse
                    Message authResponse = OpenIdProvider.buildAuthResponse(
                            requestParameters,
                            userSelectedId,
                            userSelectedClaimedId,
                            loggedUser);
                    session.setAttribute("USER_SELECTED_ID", userSelectedId);
                    session.setAttribute("USER_SELECTED_CLAIMED_ID", userSelectedClaimedId);
                    HttpServletResponse resp = (HttpServletResponse) context.getExternalContext().getResponse();
                    resp.sendRedirect(authResponse.getDestinationUrl(true));
                } else 
                    outcome = "home?faces-redirect=true";
            }
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
            context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, ex.getMessage(), ""));
        }
        return outcome;
    }
    
    public String logoutAction() {
        FacesContext context = FacesContext.getCurrentInstance();
        try{
            loggedUser = null;
            HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getRequest();
            request.getSession().invalidate();
            return "/index?faces-redirect=true";
        } catch (Exception ex) {
            logger.error(ex.getMessage(), ex);
            context.addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, ex.getMessage(), ""));
        }
        return "";
    }
    
    public boolean isUserInRole(Role.RoleCode code) {
        FacesContext context = FacesContext.getCurrentInstance();
        boolean returnVal = false;
        try {
            HttpServletRequest request = (HttpServletRequest)context.getExternalContext().getRequest();
            HttpSession session = request.getSession(false);
            Set<Role> roles = (Set<Role>) session.getAttribute("LOGGED_USER_ROLES");
            if (roles != null) {
                Iterator<Role> it = roles.iterator();
                while (it.hasNext()) {
                    Role role = it.next();
                    if (role.getCode().equals(code)) {
                        returnVal = true;
                        break;
                    }
                }
            }
        } catch (Exception e) {
            logger.error(e.getMessage(), e);
        }
        return returnVal;
    }
}
